import Tablero
import Damas
import HUnit
import Maybe

-- evaluar t para correr todos los tests
t = runTestTT allTests

allTests = test [ 
	"poner, sacar y contenido" ~: testsPonerSacarContenido,
	"mover"                    ~: testsMover,
	"movimientosPosibles"      ~: testsMovimientosPosibles,
	"foldArbol"                ~: testsFold,
	"mejorMovimiento"          ~: testMejorMovimiento,
	"podar"                    ~: testsPodar,
	"ganador"                  ~: testsGanador
	]

testsPonerSacarContenido = test [
	"contenido ( poner ficha ) = ficha" ~: contenido g_2 (poner g_2 _b vacio) ~=? Just _b,
	"contenido ( sacar ( poner ficha ) ) = Nothing" ~: contenido g_2 (sacar g_2 (poner g_2 _b vacio)) ~=? Nothing,
	"pongo 2 fichas en el mismo casillero, y deberia quedar la segunda" ~:
		contenido g_2 (poner g_2 _n (poner g_2 _b vacio)) ~=? Just _n
	]

testsMover = test [
	"mover con origen vacio" ~:
		case (mover (M c_5 TL) (J Blanca vacio)) of {Nothing -> True; otherwise -> False} ~=? True,
	"origen fuera del tablero" ~:
		case (mover (M ('a', 9) TL) (J Blanca tableroInicial)) of {Nothing -> True; otherwise -> False} ~=? True,
	"destino fuera del tablero" ~:
		case (mover (M a_3 TL) (J Blanca tableroInicial)) of {Nothing -> True; otherwise -> False} ~=? True,
	"que un jugador solamente pueda mover sus fichas" ~:
		case (mover (M a_3 TR) (J Negra tableroInicial)) of {Nothing -> True; otherwise -> False} ~=? True,
	"que la ficha no se mueva en direccion incorrecta" ~:
		case (mover (M a_3 BR) (J Blanca (poner a_3 _b vacio))) of {Nothing -> True; otherwise -> False} ~=? True,
	"que el destino esté libre" ~:
		case (mover (M a_3 TR) (J Blanca (poner c_5 _n (poner b_4 _n (poner a_3 _b vacio))))) of {Nothing -> True; otherwise -> False} ~=? True,
	"que no se pueda capturar una ficha del mismo color" ~:
		case (mover (M a_3 TR) (J Blanca (poner b_4 _b (poner a_3 _b vacio)))) of {Nothing -> True; otherwise -> False} ~=? True,
	"movimiento simple" ~:
		case (mover (M a_3 TR) (J Blanca tableroInicial)) of {Just _ -> True; otherwise -> False} ~=? True,
	"movimiento captura" ~:
		case (mover (M a_3 TR) (J Blanca (poner a_3 _b (poner b_4 _n vacio)))) of {Just _ -> True; otherwise -> False} ~=? True,
	"movimiento simple + coronacion" ~:
		let Just (J c tablero) = (mover (M a_7 TR) (J Blanca (poner a_7 _b vacio))) in contenido b_8 tablero ~=? Just _B,
	"movimiento captura + coronacion" ~:
		let Just (J c tablero) = (mover (M a_6 TR) (J Blanca (poner b_7 _n (poner a_6 _b vacio)))) in contenido c_8 tablero ~=? Just _B
	]

testsMovimientosPosibles = test [
	"simple blanca se mueve TL y TR" ~:
		map (\x -> fst x) (movimientosPosibles (J Blanca (poner c_5 _b vacio))) ~~? [M c_5 TL, M c_5 TR],
	"reina blanca se mueve TL, TR, BL y BR" ~:
		map (\x -> fst x) (movimientosPosibles (J Blanca (poner c_5 _B vacio))) ~~? [M c_5 TL, M c_5 TR, M c_5 BL, M c_5 BR],
	"simple blanca c_5 con b_6 ocupado se mueve TR y b_6 TL y TR" ~:
		map (\x -> fst x) (movimientosPosibles (J Blanca (poner c_5 _b (poner b_6 _b vacio)))) ~~? [M c_5 TR, M b_6 TL, M b_6 TR],
	"simple blanca c_5 con negra en b_6 se mueve TL y TR" ~:
		map (\x -> fst x) (movimientosPosibles (J Blanca (poner c_5 _b (poner b_6 _n vacio)))) ~~? [M c_5 TL, M c_5 TR],
	"sin fichas no hay movimientos posibles" ~:
		map (\x -> fst x) (movimientosPosibles (J Blanca vacio)) ~~? []
	]

testsGanador = test [
	"juego sin ganador devuelve Nothing" ~:
		ganador (J Blanca (poner d_2 _b (poner b_6 _n vacio))) ~=? Nothing,
	"juego sin fichas blancas devuelve ganador negro" ~:
		ganador (J Blanca (poner b_6 _n vacio)) ~=? Just Negra,
	"juego con fichas blancas atrapadas devuelve ganador negro" ~:
		ganador (J Blanca (poner a_7 _b (poner b_8 _n vacio))) ~=? Just Negra
	]

-- idem ~=? pero sin importar el orden
(~~?) :: (Ord a, Eq a, Show a) => [a] -> [a] -> Test
expected ~~? actual = (sort expected) ~=? (sort actual)
	where
		sort = foldl (\r e -> push r e) []
		push r e = (filter (e<=) r) ++ [e] ++ (filter (e>) r)

(~~) :: (Ord a, Eq a, Show a) => [a] -> [a] -> Bool
expected ~~ actual = (sort expected) == (sort actual)
	where
		sort = foldl (\r e -> push r e) []
		push r e = (filter (e<=) r) ++ [e] ++ (filter (e>) r)
-- cosas que agregamos...
juegoInicial :: Juego
juegoInicial = J Blanca tableroInicial

mejorMov juego n = mejorMovimiento valuacionDamas (podar n (arbolDeJugadas juego))

-- constantes para que los tests sean más legibles		
_n = Simple Negra
_N = Reina Negra
_b = Simple Blanca
_B = Reina Blanca
a_1 = ('a',1::Int)
b_1 = ('b',1::Int)
c_1 = ('c',1::Int)
d_1 = ('d',1::Int)
e_1 = ('e',1::Int)
f_1 = ('f',1::Int)
g_1 = ('g',1::Int)
h_1 = ('h',1::Int)

a_2 = ('a',2::Int)
b_2 = ('b',2::Int)
c_2 = ('c',2::Int)
d_2 = ('d',2::Int)
e_2 = ('e',2::Int)
f_2 = ('f',2::Int)
g_2 = ('g',2::Int)
h_2 = ('h',2::Int)

a_3 = ('a',3::Int)
b_3 = ('b',3::Int)
c_3 = ('c',3::Int)
d_3 = ('d',3::Int)
e_3 = ('e',3::Int)
f_3 = ('f',3::Int)
g_3 = ('g',3::Int)
h_3 = ('h',3::Int)

a_4 = ('a',4::Int)
b_4 = ('b',4::Int)
c_4 = ('c',4::Int)
d_4 = ('d',4::Int)
e_4 = ('e',4::Int)
f_4 = ('f',4::Int)
g_4 = ('g',4::Int)
h_4 = ('h',4::Int)

a_5 = ('a',5::Int)
b_5 = ('b',5::Int)
c_5 = ('c',5::Int)
d_5 = ('d',5::Int)
e_5 = ('e',5::Int)
f_5 = ('f',5::Int)
g_5 = ('g',5::Int)
h_5 = ('h',5::Int)

a_6 = ('a',6::Int)
b_6 = ('b',6::Int)
c_6 = ('c',6::Int)
d_6 = ('d',6::Int)
e_6 = ('e',6::Int)
f_6 = ('f',6::Int)
g_6 = ('g',6::Int)
h_6 = ('h',6::Int)

a_7 = ('a',7::Int)
b_7 = ('b',7::Int)
c_7 = ('c',7::Int)
d_7 = ('d',7::Int)
e_7 = ('e',7::Int)
f_7 = ('f',7::Int)
g_7 = ('g',7::Int)
h_7 = ('h',7::Int)

a_8 = ('a',8::Int)
b_8 = ('b',8::Int)
c_8 = ('c',8::Int)
d_8 = ('d',8::Int)
e_8 = ('e',8::Int)
f_8 = ('f',8::Int)
g_8 = ('g',8::Int)
h_8 = ('h',8::Int)



---------------------------------------------------------------------
-- Tests para podar

arbolInfinito :: Int ->  Arbol Int
arbolInfinito n = (Nodo n [arbolInfinito (n+1), arbolInfinito (n+1)])

arbol = arbolInfinito 1

testsFold = test["Sumar fold" ~: foldArbol (\x ss -> x + sum ss) (podar 4 arbol) ~=? (1+ 2 * 2 + 4 * 3 + 8 * 4)]


testsPodar = test["Arbol uniforme" ~: (altura (podar 1 arbol)) ~=? 1,
                  "Altura de podar" ~: (altura (podar 5 arbol)) ~=? 5,
                  "Idempotencia de podar" ~: (podar 10 (podar 10 arbol)) ~=? (podar 10 arbol)]




-----------------------------------------------------------------------
-- Tests para minimax

elTablero = poner a_7 (Reina Blanca) 
           (poner c_7 (Reina Blanca) 
           (poner e_5 (Reina Negra)
           (poner d_4 (Simple Blanca)
           (poner e_3 (Simple Blanca)
           (poner e_1 (Simple Blanca) vacio)))))
           
miJuego = J Blanca elTablero

misJugadas = podar 2 (arbolDeJugadas miJuego)

misValoraciones = foldArbol (\(ms, juego) bs-> Nodo (juego, valuacionDamas juego) bs) misJugadas

testMejorMovimiento = test ["Comer última ficha" ~: (mejorMovimiento valuacionDamas misJugadas) ~=? (M d_4 TR)]

